package com.yh.csx.crm.service;

import com.yh.csx.crm.core.exception.BusinessException;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.stereotype.Service;

import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author Huang Zhaoping
 * @date 2019/3/5
 */
@Service
public class CacheService implements DisposableBean {

    private Map<String, Item> cache = new ConcurrentHashMap<>();

    public <T> T getValue(String key, int expires, Callable<T> callable) {
        Item item = cache.get(key);
        if (item != null && !item.isExpired()) {
            return (T) item.value;
        } else {
            item = new Item();
        }
        T obj;
        try {
            obj = callable.call();
        } catch (Exception e) {
            if (e instanceof BusinessException) {
                throw (BusinessException) e;
            }
            throw new BusinessException(e.getMessage(), e);
        }
        item.value = obj;
        item.expireTime = expires <= 0 ? -1 : System.currentTimeMillis() + expires;
        cache.put(key, item);
        return obj;
    }

    public void setValue(String key, int expires, String value) {
        Item item = cache.get(key);
        if (item == null) {
            item = new Item();
        }
        item.value = value;
        item.expireTime = expires <= 0 ? -1 : System.currentTimeMillis() + expires;
        cache.put(key, item);
    }

    public <T> T getValue(String key) {
        Item item = cache.get(key);
        return item == null || item.isExpired() ? null : (T) item.value;
    }

    public <T> T removeValue(String key) {
        Item item = cache.remove(key);
        return item == null || item.isExpired() ? null : (T) item.value;
    }

    @Override
    public void destroy() throws Exception {
        cache.clear();
    }

    private class Item {
        volatile Object value;
        volatile long expireTime;

        boolean isExpired() {
            return expireTime >= 0 && expireTime < System.currentTimeMillis();
        }
    }
}
